/*--------------------------------------------------------------------------------*/
#ifndef __COMPONENT_STATE_CHART__
#define __COMPONENT_STATE_CHART__
/*--------------------------------------------------------------------------------*/
#include "primitives.h"
#include "object.h"
#include "util.h"
#include "timer.h"
#include "stack.h"
/*--------------------------------------------------------------------------------*/
class COMPONENT_STATE_CHART
{

	// -- PUBLIC

public:

	// .. TYPES

	struct EVENT_PARAMETER
	{
		INDEX
			Event;
		REF_TO_< OBJECT >
			Object;		
	};
	

    // .. CONSTRUCTORS

    COMPONENT_STATE_CHART( const INDEX initial_state ) :
    	CurrentState( initial_state ),
    	NextEventTable(),
    	StateHasChanged( false ),
    	ItMustEnterState( true ),
    	EventObject()
    {

    }

    virtual ~COMPONENT_STATE_CHART()
    {

    }

    // .. METHODS

    VOID Update( const TIMER & timer )
    {
    	CurrentTimer = & timer;

    	if( StateHasChanged )
    	{
    		Process( 2 );
    		CurrentState = NextState;
    		StateHasChanged = false;
    		ItMustEnterState = true;
    	}

    	if( ItMustEnterState )
    	{
    		Process( 1 );
    		ItMustEnterState = false;
    	}

    	Process( 3 );

    	while( !NextEventTable.IsEmpty() )
    	{
    		EventObject = NextEventTable.GetTop().Object;
	   		Process( NextEventTable.Pop().Event );
    	}

    	Process( 4 );

    }

    VOID ChangeState( const INDEX new_state )
    {
    	NextState = new_state;
    	StateHasChanged = true;
    }

    VOID LaunchEvent( const INDEX event )
    {
    	EVENT_PARAMETER
    		event_parameter;
    		
    	event_parameter.Event = event;
		event_parameter.Object.SetNull();
		
    	NextEventTable.Push( event_parameter );
    }
    
    VOID LaunchEvent( const INDEX event, const REF_TO_< OBJECT > object )
    {
    	EVENT_PARAMETER
    		event_parameter;
    		
    	event_parameter.Event = event;
		event_parameter.Object.Set( object.GetPointer() );
		
    	NextEventTable.Push( event_parameter );
    }

    virtual VOID Process( const INDEX event ) = 0;

    // -- PROTECTED

protected :

    // .. ATTRIBUTES

    INDEX
    	CurrentState,
    	NextState;
    STACK< EVENT_PARAMETER >
    	NextEventTable;
    const TIMER
    	*CurrentTimer;
    BOOL
    	StateHasChanged,
    	ItMustEnterState;
	REF_TO_< OBJECT >
		EventObject;
    
    // -- PRIVATE

private :

    COMPONENT_STATE_CHART()
    {
    }

};
/*--------------------------------------------------------------------------------*/
#define BEGIN_DECLARE_STATE_CHART( _STATE_CHART_ ) \
	class _STATE_CHART_ : public COMPONENT_STATE_CHART { \
		public: \
		virtual ~_STATE_CHART_() { } \
		virtual VOID Process( const INDEX event ); \
		_STATE_CHART_( const INDEX initial_state ) : COMPONENT_STATE_CHART( initial_state ) { }


#define DECLARE_STATES \
	enum STATE {

#define DECLARE_EVENTS \
	}; enum EVENT { NO_EVENT=0, ENTER_EVENT=1, EXIT_EVENT=2, UPDATE_EVENT=3, RENDER_EVENT=4,

#define DECLARE_ATTRIBUTES \
	}; protected:

#define DECLARE_PROTECTED \
	}; protected:

#define END_DECLARE_STATE_CHART() \
	};

#define IMPLEMENT_STATE_CHART( _STATE_CHART_ ) \
	VOID _STATE_CHART_::Process( const INDEX event )

#define IMPLEMENT_STATE( _STATE_ ) \
		if( CurrentState == _STATE_ )

#define IMPLEMENT_STATE_OnEvent( _EVENT_ ) \
			if( event == _EVENT_ )

#define IMPLEMENT_STATE_OnEnterEvent() \
			if( event == ENTER_EVENT )

#define STATE_GetTimeStep() CurrentTimer->GetSecondCount()


/*--------------------------------------------------------------------------------*/
#endif
